// Objects (对象) 示例
// 演示 Pascal 中对象的各种用法
program p_27_objects;

{$mode objfpc}{$H+}
// {$mode objfpc} 启用 Object Pascal 模式，支持面向对象编程
// {$H+} 启用长字符串支持（AnsiString）

// 引入单元文件
uses
  SysUtils;  // 系统工具单元，包含常用的系统函数

// 定义一个简单的银行账户类
type
  TBankAccount = class
  private
    FAccountNumber: String;
    FOwnerName: String;
    FBalance: Real;
  public
    constructor Create(const AAccountNumber: String; const AOwnerName: String; InitialBalance: Real);
    procedure Deposit(Amount: Real);
    function Withdraw(Amount: Real): Boolean;
    procedure DisplayAccountInfo;
    property AccountNumber: String read FAccountNumber;
    property OwnerName: String read FOwnerName;
    property Balance: Real read FBalance;
  end;

// TBankAccount类的实现
constructor TBankAccount.Create(const AAccountNumber: String; const AOwnerName: String; InitialBalance: Real);
begin
  FAccountNumber := AAccountNumber;
  FOwnerName := AOwnerName;
  if InitialBalance >= 0 then
    FBalance := InitialBalance
  else
    FBalance := 0;
end;

procedure TBankAccount.Deposit(Amount: Real);
begin
  if Amount > 0 then
  begin
    FBalance := FBalance + Amount;
    WriteLn('存款成功，存入金额: ', Amount:0:2, ' 元');
  end
  else
    WriteLn('存款金额必须大于0');
end;

function TBankAccount.Withdraw(Amount: Real): Boolean;
begin
  Result := False;
  if Amount > 0 then
  begin
    if FBalance >= Amount then
    begin
      FBalance := FBalance - Amount;
      WriteLn('取款成功，取出金额: ', Amount:0:2, ' 元');
      Result := True;
    end
    else
      WriteLn('余额不足，取款失败');
  end
  else
    WriteLn('取款金额必须大于0');
end;

procedure TBankAccount.DisplayAccountInfo;
begin
  WriteLn('账户信息:');
  WriteLn('  账号: ', FAccountNumber);
  WriteLn('  户主: ', FOwnerName);
  WriteLn('  余额: ', FBalance:0:2, ' 元');
end;

// 定义一个计算器类
type
  TCalculator = class
  public
    function Add(a, b: Real): Real;
    function Subtract(a, b: Real): Real;
    function Multiply(a, b: Real): Real;
    function Divide(a, b: Real): Real;
  end;

function TCalculator.Add(a, b: Real): Real;
begin
  Result := a + b;
end;

function TCalculator.Subtract(a, b: Real): Real;
begin
  Result := a - b;
end;

function TCalculator.Multiply(a, b: Real): Real;
begin
  Result := a * b;
end;

function TCalculator.Divide(a, b: Real): Real;
begin
  if b <> 0 then
    Result := a / b
  else
  begin
    WriteLn('错误：除数不能为零');
    Result := 0;
  end;
end;

// 程序主入口
begin
  WriteLn('=== Pascal 对象示例 ===');
  WriteLn;
  
  // 1. 创建和使用银行账户对象
  WriteLn('1. 创建和使用银行账户对象:');
  var account1: TBankAccount := TBankAccount.Create('123456789', '张三', 1000.0);
  try
    account1.DisplayAccountInfo;
    WriteLn;
    
    account1.Deposit(500.0);
    account1.DisplayAccountInfo;
    WriteLn;
    
    account1.Withdraw(200.0);
    account1.DisplayAccountInfo;
    WriteLn;
    
    account1.Withdraw(2000.0);  // 尝试取出超过余额的金额
  finally
    account1.Free;
  end;
  
  WriteLn;
  
  // 2. 创建和使用多个对象
  WriteLn('2. 创建和使用多个对象:');
  var account2: TBankAccount := TBankAccount.Create('987654321', '李四', 500.0);
  var account3: TBankAccount := TBankAccount.Create('456789123', '王五', 1500.0);
  try
    WriteLn('账户2信息:');
    account2.DisplayAccountInfo;
    WriteLn;
    
    WriteLn('账户3信息:');
    account3.DisplayAccountInfo;
  finally
    account2.Free;
    account3.Free;
  end;
  
  WriteLn;
  
  // 3. 使用计算器对象
  WriteLn('3. 使用计算器对象:');
  var calculator: TCalculator := TCalculator.Create;
  try
    var x: Real = 10.5;
    var y: Real = 3.2;
    
    WriteLn('计算示例:');
    WriteLn('  ', x:0:1, ' + ', y:0:1, ' = ', calculator.Add(x, y):0:2);
    WriteLn('  ', x:0:1, ' - ', y:0:1, ' = ', calculator.Subtract(x, y):0:2);
    WriteLn('  ', x:0:1, ' * ', y:0:1, ' = ', calculator.Multiply(x, y):0:2);
    WriteLn('  ', x:0:1, ' / ', y:0:1, ' = ', calculator.Divide(x, y):0:2);
    WriteLn('  ', x:0:1, ' / 0 = ', calculator.Divide(x, 0):0:2);
  finally
    calculator.Free;
  end;
  
  WriteLn;
  
  // 4. 对象数组的使用
  WriteLn('4. 对象数组的使用:');
  var accounts: array[1..3] of TBankAccount;
  
  accounts[1] := TBankAccount.Create('111111111', '赵六', 1000.0);
  accounts[2] := TBankAccount.Create('222222222', '钱七', 2000.0);
  accounts[3] := TBankAccount.Create('333333333', '孙八', 3000.0);
  
  try
    WriteLn('所有账户信息:');
    for var i := 1 to 3 do
    begin
      WriteLn('  账户 ', i, ':');
      accounts[i].DisplayAccountInfo;
      WriteLn;
    end;
  finally
    // 释放所有账户对象
    for var i := 1 to 3 do
      accounts[i].Free;
  end;
  
  WriteLn;
  
  // 5. 对象类型检查
  WriteLn('5. 对象类型检查:');
  var obj: TObject;
  obj := TBankAccount.Create('999999999', '测试用户', 100.0);
  
  try
    if obj is TBankAccount then
    begin
      WriteLn('对象是 TBankAccount 类型');
      var bankAccount: TBankAccount := TBankAccount(obj);
      bankAccount.DisplayAccountInfo;
    end
    else
      WriteLn('对象不是 TBankAccount 类型');
  finally
    obj.Free;
  end;
  
  WriteLn;
  WriteLn('演示了 Pascal 中对象的各种用法');
  
  // 等待用户按键，防止程序窗口立即关闭
  ReadLn;
end.